home *** CD-ROM | disk | FTP | other *** search
- /* THIS PROGRAM IS INTENDED TO HELP THOSE POOR PEOPLE WHO ARE TRYING TO
- LEARN HOW TO IMPLEMENT FILE SHARING ON A LAN.
-
- I had a tough time figuring out which functions where intended for
- file sharing on a LAN and which ones only worked for process locking.
- I have both a Novell network and a LANtastic network to play on.
-
- The following simple program demonstrates how I will implement file
- sharing in my future programs.
-
- File locking can be done in 2 ways:
- 1) For buffered I/O (streams), you can only do file locking. (You lock the
- entire file). This is done by opening the file in (O_RDONLY | SH_DENYNONE)
- mode if you wish to share the data, or (O_RDWRITE | SH_DENYALL) if you
- are updating the data. Your program simple checks to see if IT can
- lock the file. It should be fairly obvious that data cannot be
- written AND shared if it is buffered at the workstation. Example of
- this type of function is: _fsopen() or fopen().
-
- 2) With unbuffered I/O (handles), you can also do region locking. This is
- the way to go. This function requires that SHARE.EXE be loaded at the
- DOS server. (Note: NOVELL servers provide all the required functionality)
- By using lock() to control access to various regions of the file, you
- can have multiple users reading concurrently, while users can be updating
- data. There are two restrictions. You should buffer the users input
- to minimize the time that a region is locked, and you should be very
- carefull about deadlocking. deadlocking is when two programs are waiting
- for each other, with no way out.
- Deadlocking is handled very nicely with locking(), however it is
- assumed that you will not be locking the region for more than 10 secs.
-
- Unbuffered file I/O allows you to use the disk as a real time virtual
- array. I would normally use binary I/O with structures for database data.
-
- Here is how its done. The process is fairly simple:
- offset = record_num * sizeof(struct)
- len = sizeof(struct)
- buffer = &(struct[record_num])
-
- 1) For READING data:
- handle = sopen( file, O_RDONLY, O_DENYNONE | O_BINARY, S_IREAD);
- lseek(handle, offset, SEEK_SET);
- if( bytes = read(handle, buffer, len) == 0) {
- printf("error reading data"); }
- close(handle);
-
- 1) or sequencially READING data:
- handle = sopen( file, O_RDONLY, O_DENYNONE | O_BINARY, S_IREAD);
- lseek(handle, 0L, SEEK_SET);
- while (NOT EOF) {
- if( bytes = read(handle, buffer, len) == 0) {
- printf("error reading data");
- lseek(handle, len, SEEK_CUR); }
- }
- close(handle);
-
- 2) For READING/WRITING data:
- handle = sopen( file, O_RDWR, O_DENYNONE | O_BINARY, S_IREAD | S_IWRITE);
- lseek(handle, offset, SEEK_SET); or lseek(handle, len, SEEK_CUR);
- if (stat = lock(handle, offset, len) == 0) {
- write(handle, buffer, len);
- unlock(handle, offset, len);
- } else { printf("Unable to access, %s", sys_errlist[errno]) }
- close(handle);
-
- /* This sample file shows file locking on a LAN. It also works for multiple
- processes on a PC (eg DOSSHELL and windows). It implements the following:
- - if data file "TEST0000.$$$" does not exist, creates it.
- - if data file cannot be modified, abort.
- - Loop, - opening file in RDONLY mode,
- - sequentially read each record, if record cannot be read,
- skip it with a message.
- - close file.
- - check for keyboard hit.
- - On kbhit:
- - Ask for record number to edit.
- - open file in shared RDWR mode.
- - lock region for this record.
- - input from user.
- - writes data to file.
- - unlocks region.
- - close file.
-
- /* NOTE: This programs runs as BOTH the locking process and as a reading
- process. Eg. on a LAN, run this on two (or more) machines, */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <sys\stat.h>
- #include <share.h>
- #include <io.h>
- #include <conio.h>
- #include <string.h>
- #include <errno.h>
- #include <stdlib.h>
-
- #define MAXARRAY 15
- #define ESC 27
- #define OR ||
- #define AND &&
-
- struct data_st { /* I'm using a sample struct for disk IO*/
- char string[62]; /* Normally, I would consider the disk file */
- int number; /* a virtual array, with direct binary IO. */
- } data[MAXARRAY];/* Also, when sharing, all data is unbuffered */
-
- /*-----------------------------------------------------------------
- main()
- -----------------------------------------------------------------*/
- void main( void) {
- void InitFile(char *file); /*Progamming Hint: always use prototype */
- void ReadFile( char *file); /*in function which uses it :) */
- void EnterRecord(char *file);
-
- int handle;
- int count;
- int ch;
- char file[] = "test0000.$$$"; /* sample data file name*/
-
- clrscr();
- cprintf("This program demonstrates how to implement file sharing using TC 3.0.\n\r");
- cprintf("Run this program an several PC's on a lan, or several process on a PC,\n\r");
- cprintf("then edit a record on one or more systems. This is intended as an education\n\r");
- cprintf("tool using sopen(), lseek(), lock(), and unlock(). Requires SHARE be loaded.\n\r");
- gotoxy(1,25);
- cprintf("Hit ESC to exit program, Any other key to enter data");
- /* test to see if file exists */
- if ( access(file,0) != 0) {
- InitFile( file);
- }
-
- /* test to see if file is locked by R attribute :( */
- if ( access(file,6) != 0) {
- cprintf("Attrib on %s says it cannot be MODIFIED\n\r", strupr(file));
- exit(-1);
- /*Note: There seems to be a flaw in access(). See the TC 3.0 Help
- example for sample sopen(). The flaw in access() is that it should
- show file locks from other workstations, but it only shows DOS not
- allowing writes, which can only happen from an R attribute */
- }
-
- /*- Main Program-*/
- ch = 0; /* clear input from keyboard */
- do {
- ReadFile(file);
- if (kbhit()) { /* Loop until a key is hit */
- if ( (ch = getch()) != ESC) {
- EnterRecord( file);
- ch = 0;
- }
- }
- } while (ch != ESC);
- }
-
- /*-----------------------------------------------------------------
- InitFile()
- -----------------------------------------------------------------*/
- void InitFile(char *file)
- {
- int count;
- int handle;
- char junk[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- /* Fill array with unique junk */
- for (count = 0; count < MAXARRAY; count++) {
- strcpy(data[count].string, &junk[count]);
- data[count].number = 11 * count;
- }
-
- /* Open read/write, full lock*/
- handle = sopen( file, O_RDWR | O_CREAT | O_TRUNC,
- O_DENYALL | O_BINARY,
- S_IREAD|S_IWRITE);
- if (handle < 1) {
- printf("sopen failed\n");
- exit(-1);
- } else {
- /* Note: Write whole file in one burst*/
- count = write(handle, data, sizeof(data));
- /* printf("Data file created by sopen(), %d bytes written\n", count);*/
- close(handle);
- }
- }
-
- /*-----------------------------------------------------------------
- ReadFile()
- -----------------------------------------------------------------*/
- void ReadFile( char *file)
- {
- int handle;
- int bytes;
- int count;
-
- /*- Read data into memory -*/
- handle = sopen( file, O_RDWR,
- O_DENYNONE | O_BINARY,
- S_IREAD | S_IWRITE);
-
- if (handle < 1) {
- printf("sopen failed\n");
- exit(-1);
- } else {
- /*-Sequentially read all records-*/
- lseek(handle, 0l, SEEK_SET);
- for (count = 0; count < MAXARRAY; count++) {
- /*Note: read file one record at a time (virtual array)*/
- bytes = read(handle, &data[count], sizeof(data[count]));
- gotoxy(1, count +5);
- if (bytes > 0) {
- /* printdata */
- cprintf("Record %2d ", count);
- cprintf(" >%s %d<", data[count].string, data[count].number);
- clreol();
- /* lseek not needed, file pointer moved by successful read*/
- } else {
- if (errno == EACCES) { /*- Permission denied -*/
- cprintf("LOCKED!!---");
- } else {
- cprintf("Unable to access record, %s", sys_errlist[errno]);
- clreol();
- }
- lseek(handle, sizeof(data[0]), SEEK_CUR); /*Next record*/
- }
- }
- close(handle);
- }
- }
-
- /*-----------------------------------------------------------------
- EnterRecord()
- -----------------------------------------------------------------*/
- void EnterRecord(char *file)
- {
- int test;
- int handle;
- int record;
- char buffer[80];
-
- gotoxy(1,21);
- cprintf("Enter Record # to re-enter: ");
- clreol();
- scanf("%5s", buffer);
- fflush(stdin); /* flush the input stream in case of bad input */
- record = atoi(buffer);
- if ((record < MAXARRAY) || (record > 0)) {
- /*- Lock a record-*/
- handle = sopen( file, O_RDWR,
- O_DENYNONE | O_BINARY,
- S_IREAD | S_IWRITE);
-
- if (handle < 1) {
- printf("sopen failed\n");
- exit(-1);
- } else {
- test = lock( handle, (record * sizeof(data[0])), sizeof(data[0]));
- if ((test == 0) OR (errno == EINVAL)) { /* Not locked or SHARE not loaded*/
-
- /*- Data entry -*/
- /*-Note: it is poor practice to lock the record while the user enters data-*/
- /* but it the simplest to code. How do you tell if another user has */
- /* updated the record since we last looked at it? */
- cprintf("Enter new data: ");
- clreol();
- scanf("%62s", buffer);
- fflush(stdin); /* flush the input stream in case of bad input */
- strcpy(data[record].string, buffer);
-
- /*- Write new data to file here -*/
- lseek(handle, record * sizeof(data[0]), SEEK_SET);
- write( handle, &data[record].string, sizeof(data[0]));
-
- /*- Close file -*/
- unlock(handle, (record * sizeof(data[0])), sizeof(data[0]));
- } else { /*- Error of some sort -*/
- /* if (errno == EACCES) { Permission denied)
- cprintf("*");
- } else*/ {
- cprintf("Unable to access record, %s", sys_errlist[errno]);
- }
- }
- close(handle);
- }
- }
- }
-
-